// 坐标系绘制逻辑 - 与React无关的纯TypeScript代码

export interface CoordinateSystemConfig {
  width: number;
  height: number;
  unitSize: number;
}

export interface PanState {
  isPanning: boolean;
  startX: number;
  startY: number;
  offsetX: number;
  offsetY: number;
}

export interface ZoomState {
  scale: number;
  minScale: number;
  maxScale: number;
  zoomMode: 'origin' | 'mouse';
}

export interface DrawOptions {
  canvas: HTMLCanvasElement;
  config: CoordinateSystemConfig;
  panState: PanState;
  zoomState: ZoomState;
}

// 根据缩放比例动态调整网格密度
const getGridDensity = (unitSize: number, scale: number): number => {
  // 处理极端缩放值
  if (!Number.isFinite(scale) || scale === 0) {
    return 1; // 对于无限大、无限小或0缩放，使用默认密度
  }

  // 限制缩放比例，防止极端值导致性能问题
  const clampedScale = Math.max(0.001, Math.min(500, Math.abs(scale)));

  // 目标：在屏幕上保持大约每30像素一条网格线
  const targetPixelsPerLine = 30;

  // 计算在当前缩放下，每个单位对应的像素数
  const pixelsPerUnit = unitSize * clampedScale;

  // 防止除零错误和极端值
  if (pixelsPerUnit < 0.001) {
    // 缩放极小，每个单位像素数极小，需要很密的网格
    return 0.001;
  }
  if (pixelsPerUnit > 10000) {
    // 缩放极大，每个单位像素数极大，需要很疏的网格
    return 10000;
  }

  // 计算理想的网格密度
  const idealDensity = targetPixelsPerLine / pixelsPerUnit;

  // 使用对数函数来更好地处理大范围的值
  const logIdeal = Math.log10(idealDensity);

  // 将密度映射到对数空间，然后选择最接近的刻度值
  const logSteps = [
    -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  ]; // 对应 0.001, 0.01, 0.1, 1, 10, 100, 1000

  // 找到最接近的对数步长
  let bestLogStep = logSteps[0];
  for (const logStep of logSteps) {
    if (Math.abs(logStep - logIdeal) < Math.abs(bestLogStep - logIdeal)) {
      bestLogStep = logStep;
    }
  }

  // 计算基础密度值
  const baseDensity = 10 ** bestLogStep;

  // 在基础密度值附近选择最合适的倍数（1, 2, 5, 10, 20, 40）
  const multipliers = [1, 2, 5, 10, 20, 40];
  let bestDensity = baseDensity;

  for (const multiplier of multipliers) {
    const candidateDensity = baseDensity * multiplier;
    if (
      Math.abs(candidateDensity - idealDensity) <
      Math.abs(bestDensity - idealDensity)
    ) {
      bestDensity = candidateDensity;
    }
  }

  // 确保密度在合理范围内
  return Math.max(0.001, Math.min(10000, bestDensity));
};

// 根据缩放比例调整刻度密度
const getTickDensity = (unitSize: number, scale: number): number => {
  // 处理极端缩放值
  if (!Number.isFinite(scale) || scale === 0) {
    return 5; // 对于无限大、无限小或0缩放，使用默认密度
  }

  // 限制缩放比例，防止极端值导致性能问题
  const clampedScale = Math.max(0.001, Math.min(500, Math.abs(scale)));

  // 目标：在屏幕上保持大约每80像素一个刻度
  const targetPixelsPerTick = 80;

  // 计算在当前缩放下，每个单位对应的像素数
  const pixelsPerUnit = unitSize * clampedScale;

  // 防止除零错误和极端值
  if (pixelsPerUnit < 0.001) {
    return 0.001; // 缩放极小，需要很密的刻度
  }
  if (pixelsPerUnit > 10000) {
    return 10000; // 缩放极大，需要很疏的刻度
  }

  // 计算理想的刻度密度
  const idealDensity = targetPixelsPerTick / pixelsPerUnit;

  // 使用对数函数来更好地处理大范围的值
  const logIdeal = Math.log10(idealDensity);

  // 将密度映射到对数空间，然后选择最接近的刻度值
  const logSteps = [
    -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  ]; // 对应 0.001, 0.01, 0.1, 1, 10, 100, 1000

  // 找到最接近的对数步长
  let bestLogStep = logSteps[0];
  for (const logStep of logSteps) {
    if (Math.abs(logStep - logIdeal) < Math.abs(bestLogStep - logIdeal)) {
      bestLogStep = logStep;
    }
  }

  // 计算基础密度值
  const baseDensity = 10 ** bestLogStep;

  // 在基础密度值附近选择最合适的倍数（1, 2, 5）
  const multipliers = [1, 2, 5, 10, 20, 40];
  let bestDensity = baseDensity;

  for (const multiplier of multipliers) {
    const candidateDensity = baseDensity * multiplier;
    if (
      Math.abs(candidateDensity - idealDensity) <
      Math.abs(bestDensity - idealDensity)
    ) {
      bestDensity = candidateDensity;
    }
  }

  // 确保密度在合理范围内，且刻度密度比网格密度稀疏
  return Math.max(0.001, Math.min(10000, bestDensity));
};

/**
 * 绘制直角坐标系
 */
export function drawCoordinateSystem(options: DrawOptions): void {
  const { canvas, config, panState, zoomState } = options;
  const { width, height, unitSize } = config;

  const ctx = canvas.getContext('2d');
  if (!ctx) return;

  // 设置画布尺寸
  canvas.width = width;
  canvas.height = height;

  // 清除画布
  ctx.clearRect(0, 0, width, height);

  // 计算原点位置（考虑平移偏移）
  const originX = width / 2 + panState.offsetX;
  const originY = height / 2 + panState.offsetY;

  // 绘制网格线（先绘制细网格线，然后粗网格线）

  // 1. 绘制细网格线（基础网格）
  ctx.strokeStyle = '#606060';
  ctx.lineWidth = 0.5;

  // 计算细网格密度（比粗网格更密）
  const fineGridDensity = getGridDensity(unitSize, zoomState.scale);
  const fineGridSpacing = fineGridDensity * unitSize * zoomState.scale;

  // 计算细网格线范围
  const fineStartX = Math.floor(-originX / fineGridSpacing);
  const fineEndX = Math.floor((width - originX) / fineGridSpacing);
  const fineStartY = Math.floor(-originY / fineGridSpacing);
  const fineEndY = Math.floor((height - originY) / fineGridSpacing);

  // 绘制细网格线（保持每30像素一条线的设计）
  // 绘制X方向的细网格线（垂直方向）
  for (let i = fineStartX; i <= fineEndX; i++) {
    const x = originX + i * fineGridSpacing;
    ctx.beginPath();
    ctx.moveTo(x, 0);
    ctx.lineTo(x, height);
    ctx.stroke();
  }

  // 绘制Y方向的细网格线（水平方向）
  for (let j = fineStartY; j <= fineEndY; j++) {
    const y = originY + j * fineGridSpacing;
    ctx.beginPath();
    ctx.moveTo(0, y);
    ctx.lineTo(width, y);
    ctx.stroke();
  }

  // 2. 绘制粗网格线（主要网格线）
  ctx.strokeStyle = '#202020';
  ctx.lineWidth = 1;

  // 计算粗网格密度（比细网格稀疏）
  const coarseGridDensity = fineGridDensity * 5; // 每5条细网格线一条粗网格线
  const coarseGridSpacing = coarseGridDensity * unitSize * zoomState.scale;

  // 计算粗网格线范围
  const coarseStartX = Math.floor(-originX / coarseGridSpacing);
  const coarseEndX = Math.floor((width - originX) / coarseGridSpacing);
  const coarseStartY = Math.floor(-originY / coarseGridSpacing);
  const coarseEndY = Math.floor((height - originY) / coarseGridSpacing);

  // 绘制粗网格线（保持每5条细网格线一条粗网格线的设计）
  // 绘制X方向的粗网格线（垂直方向）
  for (let i = coarseStartX; i <= coarseEndX; i++) {
    const x = originX + i * coarseGridSpacing;
    ctx.beginPath();
    ctx.moveTo(x, 0);
    ctx.lineTo(x, height);
    ctx.stroke();
  }

  // 绘制Y方向的粗网格线（水平方向）
  for (let j = coarseStartY; j <= coarseEndY; j++) {
    const y = originY + j * coarseGridSpacing;
    ctx.beginPath();
    ctx.moveTo(0, y);
    ctx.lineTo(width, y);
    ctx.stroke();
  }

  // 3. 最后绘制坐标轴
  ctx.strokeStyle = '#000';
  ctx.lineWidth = 1.5;

  // X轴
  ctx.beginPath();
  ctx.moveTo(0, originY);
  ctx.lineTo(width, originY);
  ctx.stroke();

  // Y轴
  ctx.beginPath();
  ctx.moveTo(originX, 0);
  ctx.lineTo(originX, height);
  ctx.stroke();

  // 绘制坐标轴刻度
  ctx.strokeStyle = '#000';
  ctx.lineWidth = 1;
  ctx.fillStyle = '#000';
  ctx.font = '12px Arial';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';

  const tickDensity = getTickDensity(unitSize, zoomState.scale);
  const tickSpacing = tickDensity * unitSize * zoomState.scale;

  // 计算刻度范围
  const tickStartX = Math.floor(-originX / tickSpacing);
  const tickEndX = Math.floor((width - originX) / tickSpacing);
  const tickStartY = Math.floor(-originY / tickSpacing);
  const tickEndY = Math.floor((height - originY) / tickSpacing);

  // X轴刻度
  for (let i = tickStartX; i <= tickEndX; i++) {
    if (i === 0) continue; // 跳过原点

    const x = originX + i * tickSpacing;
    const tickValue = i * tickDensity;

    // 绘制刻度线
    ctx.beginPath();
    ctx.moveTo(x, originY - 5);
    ctx.lineTo(x, originY + 5);
    ctx.stroke();

    // 绘制刻度值（只在整数位置显示）
    if (tickValue % 1 === 0) {
      ctx.fillText(tickValue.toString(), x, originY + 15);
    }
  }

  // Y轴刻度
  for (let j = tickStartY; j <= tickEndY; j++) {
    if (j === 0) continue; // 跳过原点

    const y = originY + j * tickSpacing;
    const tickValue = j * tickDensity;

    // 绘制刻度线
    ctx.beginPath();
    ctx.moveTo(originX - 5, y);
    ctx.lineTo(originX + 5, y);
    ctx.stroke();

    // 绘制刻度值（只在整数位置显示）
    if (tickValue % 1 === 0) {
      ctx.fillText(tickValue.toString(), originX - 15, y);
    }
  }

  // 绘制原点标记
  ctx.fillText('O', originX - 10, originY + 15);
}

/**
 * 创建默认的平移状态
 */
export function createDefaultPanState(): PanState {
  return {
    isPanning: false,
    startX: 0,
    startY: 0,
    offsetX: 0,
    offsetY: 0,
  };
}

/**
 * 处理鼠标按下事件，更新平移状态
 */
export function handleMouseDown(
  e: MouseEvent,
  currentPanState: PanState,
): PanState {
  return {
    ...currentPanState,
    isPanning: true,
    startX: e.clientX - currentPanState.offsetX,
    startY: e.clientY - currentPanState.offsetY,
  };
}

/**
 * 处理鼠标移动事件，更新平移状态
 */
export function handleMouseMove(
  e: MouseEvent,
  currentPanState: PanState,
): PanState {
  if (!currentPanState.isPanning) return currentPanState;

  const offsetX = e.clientX - currentPanState.startX;
  const offsetY = e.clientY - currentPanState.startY;

  return {
    ...currentPanState,
    offsetX,
    offsetY,
  };
}

/**
 * 处理鼠标释放事件，更新平移状态
 */
export function handleMouseUp(currentPanState: PanState): PanState {
  return {
    ...currentPanState,
    isPanning: false,
  };
}

/**
 * 处理鼠标离开事件，更新平移状态
 */
export function handleMouseLeave(currentPanState: PanState): PanState {
  return {
    ...currentPanState,
    isPanning: false,
  };
}

/**
 * 创建默认的缩放状态
 */
export function createDefaultZoomState(
  minScale: number = -Infinity,
  maxScale: number = Infinity,
): ZoomState {
  return {
    scale: 1.0,
    minScale,
    maxScale,
    zoomMode: 'mouse',
  };
}

/**
 * 处理滚轮缩放事件
 */
export function handleWheelZoom(
  e: WheelEvent,
  currentZoomState: ZoomState,
  canvas: HTMLCanvasElement,
  currentPanState: PanState,
): { zoomState: ZoomState; panState: PanState } {
  const rect = canvas.getBoundingClientRect();
  const mouseX = e.clientX - rect.left;
  const mouseY = e.clientY - rect.top;

  const zoomIntensity = 0.1;
  const wheelDelta = e.deltaY > 0 ? -1 : 1;

  const oldScale = currentZoomState.scale;
  let newScale = oldScale * (1 + wheelDelta * zoomIntensity);

  // 设置合理的缩放范围限制，防止极端值导致性能问题
  const minScale = Math.max(currentZoomState.minScale, 0.01);
  const maxScale = Math.min(currentZoomState.maxScale, 500); // 限制最大缩放为500倍

  // 限制缩放范围
  newScale = Math.max(minScale, Math.min(maxScale, newScale));

  // 如果缩放比例没有变化，直接返回
  if (newScale === oldScale) {
    return {
      zoomState: currentZoomState,
      panState: currentPanState,
    };
  }

  const zoomState = {
    ...currentZoomState,
    scale: newScale,
  };

  // 基于缩放模式调整平移状态
  if (currentZoomState.zoomMode === 'mouse') {
    // 计算鼠标位置相对于canvas中心的比例
    const canvasCenterX = canvas.width / 2;
    const canvasCenterY = canvas.height / 2;

    // 计算鼠标位置在坐标系中的位置
    const mouseCoordX =
      (mouseX - canvasCenterX - currentPanState.offsetX) / oldScale;
    const mouseCoordY =
      (mouseY - canvasCenterY - currentPanState.offsetY) / oldScale;

    // 计算新的偏移量，使得鼠标指向的点在缩放后位置不变
    const newOffsetX = mouseX - canvasCenterX - mouseCoordX * newScale;
    const newOffsetY = mouseY - canvasCenterY - mouseCoordY * newScale;

    const panState = {
      ...currentPanState,
      offsetX: newOffsetX,
      offsetY: newOffsetY,
    };

    return { zoomState, panState };
  } else {
    // 基于原点的缩放：保持坐标系原点位置不变
    // 不需要调整平移状态
    return { zoomState, panState: currentPanState };
  }
}

/**
 * 重置缩放状态
 */
export function resetZoom(currentZoomState: ZoomState): ZoomState {
  return {
    ...currentZoomState,
    scale: 1.0,
  };
}

/**
 * 切换缩放模式
 */
export function toggleZoomMode(currentZoomState: ZoomState): ZoomState {
  const newMode = currentZoomState.zoomMode === 'origin' ? 'mouse' : 'origin';
  return {
    ...currentZoomState,
    zoomMode: newMode,
  };
}

/**
 * 计算鼠标在坐标系中的坐标
 */
export function getMouseCoordinate(
  mouseX: number,
  mouseY: number,
  canvas: HTMLCanvasElement,
  panState: PanState,
  zoomState: ZoomState,
  unitSize: number,
): { x: number; y: number } {
  const canvasCenterX = canvas.width / 2;
  const canvasCenterY = canvas.height / 2;

  // 计算鼠标在坐标系中的位置
  const coordX =
    (mouseX - canvasCenterX - panState.offsetX) / (zoomState.scale * unitSize);
  const coordY =
    (mouseY - canvasCenterY - panState.offsetY) / (zoomState.scale * unitSize);

  return {
    x: coordX,
    y: -coordY, // 反转Y轴方向（屏幕坐标系与数学坐标系相反）
  };
}
